/*
 * Copyright 2012 Marsrutai.lt
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package lt.marsrutai.mobile.android.fragment;

import java.util.ArrayList;
import java.util.List;

import lt.marsrutai.mobile.android.AppContext;
import lt.marsrutai.mobile.android.R;
import lt.marsrutai.mobile.android.activity.intent.BookmarksIntentHolder;
import lt.marsrutai.mobile.android.activity.intent.TaskIntentHolder;
import lt.marsrutai.mobile.android.fragment.task.TaskFragment;
import lt.marsrutai.mobile.android.manager.ActivityManager;
import lt.marsrutai.mobile.android.model.Bookmark;
import lt.marsrutai.mobile.android.widget.ListViewAdapter;
import lt.marsrutai.mobile.android.widget.SelectableListView;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.support.v4.content.LocalBroadcastManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;

import com.actionbarsherlock.app.SherlockListFragment;
import com.actionbarsherlock.view.ActionMode;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuInflater;
import com.actionbarsherlock.view.MenuItem;

/**
 * Base class for bookmark fragments. Contains common bookmark handling logic.
 * 
 * @author Justas
 * 
 * @param <T>
 *            Type of bookmarks to be displayed
 */
public abstract class BookmarksFragment<T extends Bookmark> extends SherlockListFragment {

    private FragmentManager fragmentManager;
    private ActivityManager manager;

    private List<T> bookmarks;

    private ListViewAdapter<T> adapter;

    /**
     * temp variable used only on state restoration
     */
    private List<Integer> selectedItems;

    private BroadcastReceiver bookmarkReceiver = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
            TaskIntentHolder holder = new TaskIntentHolder(intent);

            switch (holder.getStatus()) {
            case Activity.RESULT_OK:
                bookmarks = holder.getListResult();

                fillAdapter();
            default:
                manager.dismissDownloadLoadingBar();
            }
        }
    };

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.bookmark_list_fragment, null);
        ((TextView) view.findViewById(android.R.id.empty)).setText(getNoBookmarksFoundMessage());
        return view;
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        fragmentManager = getFragmentManager();
        manager = new ActivityManager(getActivity());
        manager.showDownloadLoadingBar();

        getListView().setActionModeCallback(new ActionModeCallback());
        
        // Restore state
        restoreState(savedInstanceState);
    }

    @Override
    public void onPause() {
        super.onPause();

        LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(bookmarkReceiver);
    }

    @Override
    public void onResume() {
        super.onResume();
        LocalBroadcastManager.getInstance(getActivity()).registerReceiver(bookmarkReceiver, new IntentFilter(getTaskBroadcastAction()));

        if (bookmarks == null) {
            // Start downloading only if we don't have any scopes, and task
            // fragments has not been retained
            if (!TaskFragment.isActive((TaskFragment<?, ?, ?>) fragmentManager.findFragmentByTag(getBookmarksTaskFragmentTag()))) {
                downloadData();
            }
        }
        else {
            // already have all the data - display it
            fillAdapter();
            manager.dismissDownloadLoadingBar();
        }
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        BookmarksIntentHolder intentHolder = new BookmarksIntentHolder(new Bundle());
        intentHolder.setBookmarks(bookmarks);

        selectedItems = new ArrayList<Integer>();

        for (Integer position : getListView().getCheckedItemPositionList()) {
            selectedItems.add(position);
        }
        intentHolder.setSelectedItems(selectedItems);

        outState.putAll(intentHolder.getIntent().getExtras());

        super.onSaveInstanceState(outState);
    }

    @Override
    public SelectableListView getListView() {
        return (SelectableListView) super.getListView();
    }

    private void restoreState(Bundle bundle) {
        bundle = bundle == null ? getArguments() : bundle;

        if (bundle == null) {
            return;
        }

        BookmarksIntentHolder intentHolder = new BookmarksIntentHolder(bundle);
        bookmarks = intentHolder.getBookmarks();
        selectedItems = intentHolder.getSelectedItems();
    }

    /**
     * Returns a task broadcast action. Used to determine whether bookmark
     * download has completed.
     * 
     * @return
     */
    protected abstract String getTaskBroadcastAction();

    /**
     * Task fragment class. Is used to start bookmark downloads.
     * 
     * @return
     */
    protected abstract Class<? extends TaskFragment<?, ?, ?>> getTaskFragmentClass();

    /**
     * Tag identifying task fragment which hosts bookmark fetching task
     * 
     * @return
     */
    protected abstract String getBookmarksTaskFragmentTag();

    /**
     * Creates a list adapter
     * 
     * @return
     */
    protected abstract ListViewAdapter<T> createAdapter();

    /**
     * Message to display when there are no bookmarks
     * 
     * @return
     */
    public abstract int getNoBookmarksFoundMessage();

    protected void fillAdapter() {
        adapter = createAdapter();
        setListAdapter(adapter);

        if (bookmarks != null && bookmarks.size() > 0) {
            for (int i = 0; i < bookmarks.size(); i++) {
                adapter.add(bookmarks.get(i));
            }
        }

        if (selectedItems != null) {
            for (Integer position : selectedItems) {
                getListView().setItemChecked(position, true);
            }
        }
    }

    public void downloadData() {
        TaskFragment.download(fragmentManager, getTaskFragmentClass(), getBookmarksTaskFragmentTag(), (String) null);
    }

    public List<T> getBookmarks() {
        return bookmarks;
    }

    public void setBookmarks(List<T> bookmarks) {
        this.bookmarks = bookmarks;
    }

    public ListViewAdapter<T> getAdapter() {
        return adapter;
    }

    public void setAdapter(ListViewAdapter<T> adapter) {
        this.adapter = adapter;
    }

    /**
     * Manages the current action mode
     * 
     * @author Justas
     */
    public static interface ActionModeManager {

        void setActionMode(ActionMode actionMode);

        ActionMode getActionMode();
    }

    private class ActionModeCallback extends SelectableListView.ActionModeCallback {

        @Override
        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
            MenuInflater inflater = mode.getMenuInflater();
            inflater.inflate(R.menu.bookmark_context_menu, menu);

            return true;
        }

        @Override
        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
            return true;
        }

        @Override
        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
            switch (item.getItemId()) {
            case R.id.remove_bookmark:
                List<T> bookmarksToRemove = new ArrayList<T>();

                // iterate through selected items
                for (Integer position : getListView().getCheckedItemPositionList()) {
                    bookmarksToRemove.add(adapter.getItem(position));
                }

                for (T bookmark : bookmarksToRemove) {
                    AppContext.getBookmarkService().removeBookmark(bookmark);
                    adapter.remove(bookmark);
                    bookmarks.remove(bookmark);
                }

                Toast.makeText(getActivity(), getActivity().getString(R.string.bookmarks_removed), Toast.LENGTH_SHORT).show();

                mode.finish();
                return true;
            default:
                return false;
            }
        }
    }

}
